package com.irdstudio.biz.drools.aop;


import com.alibaba.fastjson.JSON;
import com.irdstudio.biz.drools.beans.RuleBean;
import com.irdstudio.biz.drools.common.BizRuleAgendaFilter;
import com.irdstudio.biz.rule.service.facade.BizRuleLogDetailService;
import com.irdstudio.biz.rule.service.facade.BizRuleLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.PrintWriter;
import java.io.StringWriter;

@Aspect
@Component
public class FireRuleAspect {

    private static Logger log = LoggerFactory.getLogger(FireRuleAspect.class);

    /**
     * 规则执行接口交互切面
     */
    @Pointcut("execution(public * com.irdstudio.biz.drools.service.FireRuleService.fire(..))")
    private void firePointcut() {}

    /**
     * 规则drools执行层切面
     */
    @Pointcut("execution(public * com.irdstudio.biz.drools.service.impl.FireRuleServiceImpl.fireRule(..))")
    private void fireRulePointcut() {}

    @Autowired
    @Qualifier("bizRuleLogServiceImpl")
    private BizRuleLogService bizRuleLogService;

    @Autowired
    @Qualifier("bizRuleLogDetailServiceImpl")
    private BizRuleLogDetailService bizRuleLogDetailService;
    /**
     * 接口交互切面实现
     * @param pjp
     * @return
     */
    @Around("firePointcut()")
    public Object aroundFire(ProceedingJoinPoint pjp) throws Throwable {

        Object[] args = pjp.getArgs();
        String reqPacket = null;
        String respPacket = null;

        Object result = null;
        String message = null;
        try {
            result = pjp.proceed(args);
            try {
                RuleBean ruleBean = (RuleBean) args[0];
                ruleBean.getExecu().clear();
                reqPacket = JSON.toJSONString(ruleBean);
                respPacket = JSON.toJSONString(result);
            } catch (Exception e) {
                log.error("记录fire接口参数异常", e);
            }
            message = "执行成功";
        } catch (Exception e) {
            message = e.getMessage();
            reqPacket = JSON.toJSONString(args);
            respPacket = getStackTraceAsString(e);
            throw e;
        } finally {
            // 记录报文入库
            bizRuleLogService.newTransLogBizRuleResult((RuleBean) args[0], reqPacket, respPacket, message);
        }
        return result;
    }

    /**
     * 规则drools执行层切面实现  先aroundFire 执行
     * @param pjp
     * @return
     */
    @Around("fireRulePointcut()")
    public Object aroundfireRule(ProceedingJoinPoint pjp) throws Throwable {

        Object[] args = pjp.getArgs();
        RuleBean req = null;
        BizRuleAgendaFilter filter = null;
        RuleBean resp = null;
        try {
            req = (RuleBean) args[0];
            filter = (BizRuleAgendaFilter) args[1];
        } catch (Exception e) {
            log.error("取fireRule接口入参异常", e);
        }

        Object result = null;
        try {
            result = pjp.proceed(args);
            try {
                resp = (RuleBean) result;
            } catch (Exception e) {
                log.error("取fireRule接口出参异常", e);
            }
        } finally {
            // 记录报文入库
            bizRuleLogDetailService.newTransLogBizRuleDetailResult(req);
        }
        return result;
    }

    /**
     * 获取异常堆栈信息
     * @param e exception
     * @return stackTrace
     */
    private String getStackTraceAsString(Exception e) {
        // StringWriter将包含堆栈信息
        StringWriter stringWriter = new StringWriter();
        //必须将StringWriter封装成PrintWriter对象，
        //以满足printStackTrace的要求
        PrintWriter printWriter = new PrintWriter(stringWriter);
        //获取堆栈信息
        e.printStackTrace(printWriter);
        //转换成String，并返回该String
        StringBuffer error = stringWriter.getBuffer();
        return error.toString();
    }
}
